package routes

import (
	"go_study/controllers"
	"io"
	"time"

	"github.com/gin-gonic/gin"

	"bytes"
	"os"

	log "github.com/sirupsen/logrus"
)

func SetUpRouter() *gin.Engine {

	// 创建日志文件（追加模式）
	f, _ := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)

	// 设置日志输出（同时输出到文件和控制台）
	gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
	r := gin.Default()
	r.Use(RequestLogger()) // 使用自定义的请求日志中间件
	// 使用 Logger 和 Recovery 中间件
	r.GET("/users", controllers.GetUsers)
	r.GET("/users/:id", controllers.GetUser)
	r.POST("/users", controllers.CreateUser)
	r.PUT("/users/:id", controllers.UpdateUser)
	r.DELETE("/users/:id", controllers.DeleteUser)
	return r
}

func RequestLogger() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()

		// 读取请求体（会清空，所以要复制）
		var bodyBytes []byte
		if c.Request.Body != nil {
			bodyBytes, _ = io.ReadAll(c.Request.Body)
		}
		c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) // 恢复请求体供后续使用

		// 捕获响应体
		respBody := new(bytes.Buffer)
		writer := &responseWriter{body: respBody, ResponseWriter: c.Writer}
		c.Writer = writer

		// 处理请求
		c.Next()

		duration := time.Since(start)

		log.Infof("➡️  %s %s | Params: %s | Status: %d | Duration: %v | Response: %s\n",
			c.Request.Method,
			c.Request.URL.Path,
			string(bodyBytes),
			c.Writer.Status(),
			duration,
			respBody.String(),
		)
	}
}

// 自定义中间件，用于将 Logrus 集成到 Gin 中
func LogrusMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 捕获响应内容
		var responseBuffer bytes.Buffer
		c.Writer = &responseWriter{
			ResponseWriter: c.Writer,
			body:           &responseBuffer,
		}

		// 在请求开始时记录日志
		log.Infof("Request: %s %s", c.Request.Method, c.Request.URL.Path)

		// 继续处理请求
		c.Next()

		responseBody := responseBuffer.String()
		// 在请求结束时记录日志
		log.Infof("Response: %d %s %s", c.Writer.Status(), responseBody, c.Request.URL.Path)
	}
}

// 自定义的 ResponseWriter 结构体，用于捕获响应内容
type responseWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

func (rw *responseWriter) Write(p []byte) (int, error) {
	rw.body.Write(p)
	return rw.ResponseWriter.Write(p)
}
